﻿using ExDUIR.NET.Declaration;
using ExDUIR.NET.Handle;
using ExDUIR.NET.Path;
using System.Runtime.InteropServices;

namespace ExDUIR.NET.Region
{
    public class ExRegion
    {
        private readonly ExRegionHandle _handle;
        public bool IsValid => _handle.IsInvalid;
        public IntPtr Handle => _handle.Handle;

        internal ExRegion(ExRegionHandle handle)
        {
            _handle = handle;
        }

        internal ExRegion(ExPath path)
        {
            _handle = new ExRegionHandle(ExAPI._rgn_createfrompath(path.Handle));
        }

        internal ExRegion(float left, float top, float right, float bottom)
        {
            _handle = new ExRegionHandle(ExAPI._rgn_createfromrect(left, top, right, bottom));
        }

        internal ExRegion(float left, float top, float right, float bottom, float radiusX, float radiusY)
        {
            _handle = new ExRegionHandle(ExAPI._rgn_createfromroundrect(left, top, right, bottom, radiusX, radiusY));
        }

        public ExRegion Combine(ExRegion RgnDst,int nCombineMode,int dstOffsetX,int dstOffsetY)
        {
            var ret = ExAPI._rgn_combine(_handle.Handle, RgnDst.Handle, nCombineMode, dstOffsetX, dstOffsetY);
            return new ExRegion(new ExRegionHandle(ret));
        }

        public bool GetLines(ref List<ExPointF> points, ref int pointsCount)
        {
            var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(ExPointF)));
            var ret = ExAPI._rgn_getlines(_handle.Handle, ref ptr, ref pointsCount);
            for (int i = 0; i < pointsCount; i++)
            {
                IntPtr targetPtrX = IntPtr.Add(ptr, i * 8);
                float x = Marshal.PtrToStructure<float>(targetPtrX);
                IntPtr targetPtrY = IntPtr.Add(ptr, i * 8 + 4);
                float y = Marshal.PtrToStructure<float>(targetPtrY);
                ExPointF point = new ExPointF(x, y);
                points.Add(point);
            }
            Marshal.FreeHGlobal(ptr);
            return ret;
        }

        public bool HitTest(float x, float y)
        {
            return ExAPI._rgn_hittest(_handle.Handle, x, y);
        }

        public bool HitTest2(ExRegion region, ref int retRelation)
        {
            return ExAPI._rgn_hittest2(_handle.Handle, region.Handle, out retRelation);
        }

        public ExRectF Bounds
        {
            get
            {
                ExRectF lpBounds = new ExRectF();
                ExAPI._rgn_getbounds(_handle.Handle, ref lpBounds);
                return lpBounds;
            }
        }

        public void Dispose() => _handle.Dispose();
    }
}
